package com.miplus.ccrm.core.service.strategy;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.miplus.ccrm.common.CmdResVo;
import com.miplus.ccrm.common.EnumRCode;
import com.miplus.ccrm.common.JPubUtils;
import com.miplus.ccrm.common.ServiceException;
import com.miplus.ccrm.core.controller.vo.LabelResVo;
import com.miplus.ccrm.core.controller.vo.strategy.ScriptEditVo;
import com.miplus.ccrm.core.controller.vo.strategy.ScriptReqVo;
import com.miplus.ccrm.core.controller.vo.strategy.ScriptResVo;
import com.miplus.ccrm.core.mapper.NmScriptMapper;
import com.miplus.ccrm.core.mapper.NmScriptRouteMapper;
import com.miplus.ccrm.core.pojo.*;
import com.miplus.ccrm.core.mapper.CpScriptTempMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
* @author pc
* @description 针对表【CP_SCRIPT_TEMP(画布流程设置模板表)】的数据库操作Service实现
* @createDate 2024-11-17 14:34:41
*/
@Slf4j
@Service
public class CpScriptTempServiceImpl extends MPJBaseServiceImpl<CpScriptTempMapper, CpScriptTemp>
    implements CpScriptTempService{
    @Value("${ccrm.ivrrec.path:}")
    private String cti_ivrRecfileDir;
    @Value("${ai.tts.url:}")
    private String ai_ttsUrl;
    @Value("${ccrm.dialer.url:}")
    private String dialer_url;
    //是否自动保存对话内容
    @Value("${ccrm.ivrasr.autosave:}")
    private Boolean cti_ivrasrAutoSave;
    //是否自动开启录音
    @Value("${ccrm.ivrrec.enable:}")
    private Boolean cti_ivrrecenable;
    @Value("${ai.tts.speed:}")
    private String tts_speed;
    @Value("${ai.tts.volume:}")
    private String tts_volume;
    @Resource
    private NmScriptMapper nmScriptMapper;
    @Resource
    private NmScriptRouteMapper scriptRouteMapper;

    @Override
    public IPage<ScriptResVo> scriptList(ScriptReqVo paras)
    {
        return selectJoinListPage(new Page<>(paras.getPageNum(), paras.getPageSize()),
                ScriptResVo.class,
                new MPJLambdaWrapper<CpScriptTemp>()
                        .selectAs("dbo.fun_getnames('PUBLIC.OPEN',t.status)",ScriptResVo::getStatusdsc)
                        .selectAll(CpScriptTemp.class)
                        .like(JPubUtils.IsNotEmpty(paras.getTemplatename()),CpScriptTemp::getTemplatename,paras.getTemplatename())
                        .eq(JPubUtils.IsNotEmpty(paras.getStatus()),CpScriptTemp::getStatus,paras.getStatus())
                        .orderByAsc(CpScriptTemp::getMddt)
        );
    }

    @Override
    public List<LabelResVo> getTempList()
    {
        return selectJoinList(LabelResVo.class,
                new MPJLambdaWrapper<CpScriptTemp>()
                        .selectAs(CpScriptTemp::getTemplateid,LabelResVo::getValue)
                        .selectAs(CpScriptTemp::getTemplatename,LabelResVo::getLabel)
                        .selectAll(CpScriptTemp.class)
        );
    }

    @Override
    public CmdResVo scriptUpdate(String $usrid, ScriptEditVo paras)
    {
        CpScriptTemp def=new CpScriptTemp();

        BeanUtils.copyProperties(paras,def);
        if(JPubUtils.IsEqual(paras.getStatus(),"1")) {
            def.setUptodt(new Date());
        }
        def.setMddt(new Date());
        def.setMdusr($usrid);
        int ret=baseMapper.updateById(def);

        if(JPubUtils.IsEqual(paras.getStatus(),"1")){
            pullRouteTable(paras.getTemplateid(),
                    paras.getUpto(),
                    paras.getJsscripttxt()
            );
        }
        else {
            downRouteTable(paras.getTemplateid());
        }

        return new CmdResVo(ret,def.getTemplateid().toString());
    }

    @Override
    public CmdResVo scriptInsert(String $usrid,ScriptEditVo paras)
    {
        CpScriptTemp def=new CpScriptTemp();

        BeanUtils.copyProperties(paras,def);
        if(JPubUtils.IsEqual(paras.getStatus(),"1")) {
            def.setUptodt(new Date());
        }
        def.setMddt(new Date());
        def.setMdusr($usrid);
        int ret=baseMapper.insert(def);

        if(JPubUtils.IsEqual(paras.getStatus(),"1")){
            pullRouteTable(def.getTemplateid(),
                    paras.getUpto(),
                    paras.getJsscripttxt()
            );
        }
        else {
            downRouteTable(def.getTemplateid());
        }

        return new CmdResVo(ret,def.getTemplateid().toString());
    }

    @Override
    public CmdResVo scriptDelete(Integer scriptid)
    {
        int ret=baseMapper.deleteById(scriptid);
        downRouteTable(scriptid);
        return new CmdResVo(ret);
    }

    private void downRouteTable(Integer scriptid)
    {
        String tempid="DIAL"+scriptid.toString();
        nmScriptMapper.deleteById(tempid);
        scriptRouteMapper.delete(new QueryWrapper<NmScriptRoute>()
                .eq("scriptid",scriptid.toString())
        );
    }

    @Override
    public ScriptResVo getSciptDetail(Integer tempid)
    {
        return selectJoinOne(ScriptResVo.class,
                new MPJLambdaWrapper<CpScriptTemp>()
                        .eq(CpScriptTemp::getTemplateid,tempid)
        );
    }

    private void pullRouteTable(Integer tempid,String subid,String scripttxt)
    {
        String scriptid="DIAL"+tempid.toString();
        NmScript script=nmScriptMapper.selectById(scriptid);
        try {
            if (script == null) {
                NmScriptRoute route = new NmScriptRoute();
                route.setChannel("Voice");
                route.setAppid("v01");
                route.setSubid(subid);
                route.setScriptid(scriptid);
                scriptRouteMapper.insert(route);

                script = new NmScript();
                script.setScriptid(scriptid);
                script.setName("AI外呼");
                script.setContent(scripttxt);
                nmScriptMapper.insert(script);
            } else {
                script.setContent(scripttxt);
                nmScriptMapper.updateById(script);
            }
        }
        catch (Exception err){
            log.info("pullRouteTable:{}",err);
            throw new ServiceException(EnumRCode.ScriptDataErr.value, err.getMessage());
        }
    }

    @Override
    public CmdResVo buildRobotScript(String scripttxt)
    {
        JSONObject jsonObject= JSONObject.parseObject(scripttxt);
        JSONArray nodes=jsonObject.getJSONArray("nodes");
        JSONArray edges=jsonObject.getJSONArray("edges");
        if(nodes==null||nodes.size()<2||edges==null){
            throw new ServiceException(EnumRCode.ScriptDataErr.value, EnumRCode.ScriptDataErr.name);
        }
        JSONObject startObj=findNodeByFlag(nodes,"start");
        if(startObj==null){
            throw new ServiceException(EnumRCode.ScriptDataErr.value, EnumRCode.ScriptDataErr.name);
        }
        String dailerUrl=dialer_url;
        if(!dailerUrl.endsWith("/")){
            dailerUrl+="/";
        }
        dailerUrl+="dialer/session/result";

        log.info("buildRobotScript:dialerurl={}..",dailerUrl);
        String nextNodeID=findNextNodeID(edges,startObj);
        JSONObject nextNode=findNextNode(nodes,nextNodeID);

        StringBuilder jsScript=new StringBuilder();

        jsScript.append("var fromUser = session.fromUser;").append("\n");
        jsScript.append("var channel = session.channel;").append("\n");
        jsScript.append("var appId = session.appId;").append("\n");
        jsScript.append("var instanceId = session.instanceId").append("\n");
        jsScript.append("var callData = session.callData;").append("\n");
        jsScript.append("var dnis = session.dnis;").append("\n");
        jsScript.append("var callId = session.callId;").append("\n");
        jsScript.append("var caseId = session.caseId;").append("\n");
        jsScript.append("var opeId = session.opeId;").append("\n");

        jsScript.append("var v_caseId = session.data;").append("\n");
        jsScript.append("var v_callcaseId = session.caseId;").append("\n");
        jsScript.append("var v_callId = session.callId;").append("\n");
        jsScript.append("var v_recordid = \"T\"+new Date().getTime()+v_caseId;").append("\n");
        jsScript.append("var v_localip = site.ip;").append("\n");
        jsScript.append("var tts_voice = \"aixia\";").append("\n\n");

        jsScript.append("Date.prototype.format = function (fmt) {").append("\n\t");
        jsScript.append("var o = {\"M+\": this.getMonth() + 1, \"d+\": this.getDate(),\"h+\": this.getHours(), \"m+\": this.getMinutes(), \"s+\": this.getSeconds(), \"q+\": Math.floor((this.getMonth() + 3) / 3), S: this.getMilliseconds()};").append("\n\t");
        jsScript.append("if(/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1,(this.getFullYear() + \"\").substr(4 - RegExp.$1.length));").append("\n\t");
        jsScript.append("for(var k in o)").append("\n\t\t");
        jsScript.append("if(new RegExp(\"(\" + k + \")\").test(fmt)) fmt = fmt.replace(RegExp.$1,RegExp.$1.length == 1 ? o[k] : (\"00\" + o[k]).substr((\"\" + o[k]).length));").append("\n\t");
        jsScript.append("return fmt;").append("\n");
        jsScript.append("}").append("\n\n");

        jsScript.append("function speakOnly(text, flowing) {").append("\n\t");
        jsScript.append("if (!flowing) flowing = \"stop\";").append("\n\t");
        jsScript.append("let flowingStr = \"\";").append("\n\t");
        jsScript.append("if (flowing) {").append("\n\t\t");
        jsScript.append("flowingStr = \"flowing=\" + flowing;").append("\n\t");
        jsScript.append("}").append("\n");
        jsScript.append("var ret = session.speak(").append("\n");
        jsScript.append(" \"{\" + flowingStr + \"}\" + text,").append("\n");
        jsScript.append("1,").append("\n");
        jsScript.append("\"speech_ali\",").append("\n");
        jsScript.append("\"siyue {appkey=80uMxWNCRpucZXRX,volume=80,speed=-160}\",").append("\n");
        jsScript.append(");").append("\n");
        jsScript.append("return ret;").append("\n");
        jsScript.append("}").append("\n\n");

        jsScript.append("function startRecord() {").append("\n\t");
        jsScript.append("let now = new Date();").append("\n\t");
        if(!cti_ivrRecfileDir.endsWith("/")){
            cti_ivrRecfileDir+="/";
        }
        jsScript.append("var filepath = \""+cti_ivrRecfileDir +"\"+ now.format('yyyyMMdd') + \"/\";").append("\n\t");
        jsScript.append("var filename = v_recordid + \".mp3\";").append("\n\t");
        jsScript.append("let data = { recordid: v_recordid, filename: filename, filepath: filepath, ani: fromUser, dnis: dnis, callcaseid: v_callcaseId, localip: v_localip };").append("\n\t");
        jsScript.append("Log.Debug(\"Script.startRecord...:\" + JSON.stringify(data));").append("\n\t");
        jsScript.append("ScriptData.saveData(\"robot\", \"session\", \"startrecord\", data);").append("\n\t");
        jsScript.append("session.record(filepath + filename, 1, 60,true);").append("\n\t");
        jsScript.append("return true;").append("\n");
        jsScript.append("}").append("\n\n");

        jsScript.append("function setDialResult(s_recid,s_ccc) {").append("\n\t");
        jsScript.append("var client = httpClient;").append("\n\t");
        jsScript.append("var body = { cmd: \"result\", recid: s_recid, ccc: s_ccc }").append("\n\t\t");
        jsScript.append("var reqcontent = new StringContent(JSON.stringify(body));").append("\n\t\t");
        jsScript.append("var url = \""+dailerUrl+"?callid=\"+"+"v_callId;").append("\n\t\t");
        jsScript.append("Log.Debug(\"script.setDialResult(\" + url + \"):\" + reqcontent);").append("\n\t\t");
        jsScript.append("var retcontent = client.Post(url, reqcontent).ReadAsString();").append("\n\t\t");
        jsScript.append("Log.Debug(\"script.setDialResult.resp:\" + retcontent);").append("\n\t\t");
        jsScript.append("}\n\n");

        jsScript.append("async function getInput(option) {").append("\n\t");
        jsScript.append("try {").append("\n\t");
        jsScript.append("let ret = await session.getInput(option);").append("\n\t\t");
        jsScript.append("return JSON.parse(ret);").append("\n\t\t");
        jsScript.append("} catch (error) {").append("\n\t\t");
        jsScript.append("Log.Error(\"获取输入失败: \" + error.message);").append("\n\t\t");
        jsScript.append("return null;").append("\n\t\t");
        jsScript.append("}").append("\n\t\t");
        jsScript.append("}\n\n");

        jsScript.append("function onDisconnect() {").append("\n\t");
        jsScript.append("let data = { recordid: v_recordid };").append("\n\t");
        jsScript.append("Log.Debug(\"Script.stopRecord...:\" + JSON.stringify(data));").append("\n\t\t");
        jsScript.append("ScriptData.saveData(\"robot\", \"session\", \"stoprecord\", data);").append("\n\t\t");
        jsScript.append("Log.Debug(\"会话已断开\");").append("\n\t\t");
        jsScript.append("}\n\n");

        jsScript.append("(async function main() {").append("\n\t");
        jsScript.append("try {").append("\n\t");
        jsScript.append("startRecord();").append("\n\t");
        getCont(jsScript,nextNode,1);
        jsScript.append("speakOnly(content);").append("\n\t\t");
        jsScript.append("await getInput({ timeout: 0 });").append("\n\t\t");
        jsScript.append("Log.Debug(\"通知文本播放完毕\");").append("\n\t\t");
        jsScript.append("setDialResult(v_caseId, 'OK');").append("\n\t\t");
        jsScript.append("let data = { speaker: \"ivr\", callcaseid: v_callcaseId, content: content };").append("\n\t\t");
        jsScript.append("Log.Debug(\"保存通知文本参数:\" + JSON.stringify(data));").append("\n\t\t");
        jsScript.append("ScriptData.saveData(\"robot\", \"session\", \"savedialogue\", data);").append("\n\t\t");
        jsScript.append("Log.Debug(\"保存通知文本完毕\");").append("\n\t\t");
        jsScript.append("session.hangup();").append("\n\t\t");
        jsScript.append("} catch (error) {").append("\n\t\t");
        jsScript.append("Log.Error(\"主流程发生错误: \" + error.message);").append("\n\t\t");
        jsScript.append("speakOnly(\"系统发生错误，请稍后再试。\");").append("\n\t\t");
        jsScript.append("await getInput({ timeout: 0 });").append("\n\t\t");
        jsScript.append("session.hangup();").append("\n\t\t");
        jsScript.append("}").append("\n\t\t");
        jsScript.append("})();").append("\n\t\t");

        String ret=jsScript.toString();
        log.info("buildRobotScript:{}",ret);

        return new CmdResVo(1,ret);
    }

    //@Override
    public CmdResVo buildRobotScriptt(String scripttxt)
    {
        JSONObject jsonObject= JSONObject.parseObject(scripttxt);
        JSONArray nodes=jsonObject.getJSONArray("nodes");
        JSONArray edges=jsonObject.getJSONArray("edges");
        if(nodes==null||nodes.size()<2||edges==null){
            throw new ServiceException(EnumRCode.ScriptDataErr.value, EnumRCode.ScriptDataErr.name);
        }
        JSONObject startObj=findNodeByFlag(nodes,"start");
        if(startObj==null){
            throw new ServiceException(EnumRCode.ScriptDataErr.value, EnumRCode.ScriptDataErr.name);
        }
        String dailerUrl=dialer_url;
        if(!dailerUrl.endsWith("/")){
            dailerUrl+="/";
        }
        dailerUrl+="dialer/session/result";

        log.info("buildRobotScript:dialerurl={}..",dailerUrl);
        String nextNodeID=findNextNodeID(edges,startObj);
        JSONObject nextNode=findNextNode(nodes,nextNodeID);

        StringBuilder jsScript=new StringBuilder();

        jsScript.append("var v_caseId = session.data;").append("\n");
        jsScript.append("var v_callcaseId = session.caseId;").append("\n");
        jsScript.append("var v_callId = session.callId;").append("\n");
        jsScript.append("var fromUser = session.fromUser;").append("\n");
        jsScript.append("var dnis = session.dnis;").append("\n");
        jsScript.append("var v_localip = site.ip;").append("\n");
        jsScript.append("var v_recordid = \"T\"+new Date().getTime()+v_caseId;").append("\n");
        jsScript.append("var tts_posturl = \""+ai_ttsUrl+"/dotctts\";").append("\n");
        jsScript.append("var tts_playurl = \""+ai_ttsUrl+"/tts/\";").append("\n");

        jsScript.append("Date.prototype.format = function (fmt) {").append("\n\t");
        jsScript.append("var o = {\"M+\": this.getMonth() + 1, \"d+\": this.getDate(),\"h+\": this.getHours(), \"m+\": this.getMinutes(), \"s+\": this.getSeconds(), \"q+\": Math.floor((this.getMonth() + 3) / 3), S: this.getMilliseconds()};").append("\n\t");
        jsScript.append("if(/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1,(this.getFullYear() + \"\").substr(4 - RegExp.$1.length));").append("\n\t");
        jsScript.append("for(var k in o)").append("\n\t\t");
        jsScript.append("if(new RegExp(\"(\" + k + \")\").test(fmt)) fmt = fmt.replace(RegExp.$1,RegExp.$1.length == 1 ? o[k] : (\"00\" + o[k]).substr((\"\" + o[k]).length));").append("\n\t");
        jsScript.append("return fmt;").append("\n");
        jsScript.append("}").append("\n\n");

        jsScript.append("function getData(path, type, key, paras) {").append("\n\t");
        jsScript.append("let ret = ScriptData.getData(path, type, key, paras);").append("\n\t");
        jsScript.append("let result = JSON.parse(ret);").append("\n\t");
        jsScript.append("Log.Debug(\"Script.getdata result: \" +result.Cause +\", Code: \" +result.Code +\", Count: \" + (result.Data && result.Data.length));").append("\n\t");
        jsScript.append("if(result.Code == 0 && result.Data && result.Data.length) {").append("\n\t\t");
        jsScript.append("return result.Data[0];").append("\n\t");
        jsScript.append("} else return null;").append("\n");
        jsScript.append("}").append("\n\n");

        //jsScript.append("async function waitConnect() {").append("\n\t");
        //jsScript.append("while (session.connected) {").append("\n\t");
        //jsScript.append("let message = await session.getMessage(10);").append("\n\t");
        //jsScript.append("if (message) {").append("\n\t\t");
        //jsScript.append("let msg = JSON.parse(message.ToString());").append("\n\t\t");
        //jsScript.append("if (msg[\"event\"] === \"line\" && msg[\"status\"] === \"connect\") {").append("\n\t\t\t");
        //jsScript.append("return;").append("\n\t\t");
        //jsScript.append("}").append("\n\t");
        //jsScript.append("}").append("\n\t");
        //jsScript.append("}").append("\n");
        //jsScript.append("}").append("\n\n");

        jsScript.append("function recognizeOnly() {").append("\n\t");
        jsScript.append("session.startRecognize(\"talented {rate=8000,no-input-timeout=5000,speech-timeout=800}\");").append("\n");
        jsScript.append("}\n\n");

        jsScript.append("function startRecord() {").append("\n\t");
        jsScript.append("let now = new Date();").append("\n\t");
        if(!cti_ivrRecfileDir.endsWith("/")){
            cti_ivrRecfileDir+="/";
        }
        jsScript.append("var filepath = \""+cti_ivrRecfileDir +"\"+ now.format('yyyyMMdd') + \"/\";").append("\n\t");
        jsScript.append("var filename = v_recordid + \".mp3\";").append("\n\t");
        jsScript.append("var data = {recordid:v_recordid,filename:filename,filepath:filepath,ani:fromUser,dnis:dnis,callcaseid:v_callcaseId,localip:v_localip};").append("\n\t");
        jsScript.append("Log.Debug(\"Script.startRecord...:\" + JSON.stringify(data));").append("\n\t");
        jsScript.append("ScriptData.saveData(\"robot\", \"session\", \"startrecord\", data);").append("\n\t");
        jsScript.append("session.record(filepath + filename, 1, 60,true);").append("\n\t");
        jsScript.append("return true;").append("\n");
        jsScript.append("}").append("\n\n");

        jsScript.append("function speakwithDetect(s_usrid,s_content){").append("\n\t");
        jsScript.append("try {").append("\n\t\t");
        jsScript.append("var body = {userid:s_usrid,token:\"1234567890\",spkid:\"0\",lanid:\"1\",speed:"+tts_speed+",volume:"+tts_volume+",content:s_content}").append("\n\t\t");
        jsScript.append("var reqcontent = new StringContent(JSON.stringify(body));").append("\n\t\t");
        jsScript.append("var url = tts_posturl+\"?userid=\" + s_usrid + \"&token=1234567890&spkid=0&lanid=1&speed="+tts_speed+"&volume="+tts_volume+"&content=\" + encodeURIComponent(s_content);").append("\n\t\t");
        jsScript.append("Log.Debug(\"script.speakwithDetect ttsurl:\" + url);").append("\n\t\t");
        jsScript.append("var tts_content = httpClient.Post(url,reqcontent).ReadAsString();").append("\n\t\t");
        jsScript.append("Log.Debug(\"script.speakWithDetect ttsResp:\" + tts_content);").append("\n\t\t");
        jsScript.append("return tts_content;").append("\n\t");
        jsScript.append("} catch {").append("\n\t\t");
        jsScript.append("Log.Debug(\"script.speakWithDetect Err:\" + e);").append("\n\t\t");
        jsScript.append("return \"\";").append("\n\t");
        jsScript.append("}").append("\n");
        jsScript.append("}").append("\n\n");

        jsScript.append("function setDialResult(s_recid,s_ccc) {").append("\n\t");
        jsScript.append("var client = httpClient;").append("\n\t");
        jsScript.append("var body = {cmd:\"result\",recid:s_recid,ccc:s_ccc}").append("\n\t\t");
        jsScript.append("var reqcontent = new StringContent(JSON.stringify(body));").append("\n\t\t");
        jsScript.append("var url = \""+dailerUrl+"?callid=\"+"+"v_callId;").append("\n\t\t");
        jsScript.append("Log.Debug(\"script.setDialResult(\" + url+\"):\"+reqcontent);").append("\n\t\t");
        jsScript.append("var retcontent = client.Post(url,reqcontent).ReadAsString();").append("\n\t\t");
        jsScript.append("Log.Debug(\"script.setDialResult.resp:\" + retcontent);").append("\n\t\t");
        jsScript.append("}\n\n");

        jsScript.append("(async function () {").append("\n\t");
        //jsScript.append("session.answer();").append("\n\t");
        if(cti_ivrrecenable) {
            jsScript.append("startRecord();").append("\n\t");
        }
        String nodeType=getNodeType(nextNode);
        String func=getNodeFunc(nextNode);
        if(JPubUtils.IsEqual(nodeType,"play")) { //是否本人
            addPlayNode(jsScript,nextNode,0);
            nextNodeID=findNextNodeID(edges,nextNode);
            nextNode=findNextNode(nodes,nextNodeID);
            nodeType=getNodeType(nextNode);
            func=getNodeFunc(nextNode);
        }

        if(JPubUtils.IsEqual(nodeType,"waitresponse")) {
            jsScript.append("\t");
            jsScript.append("recognizeOnly();").append("\n\t");
            if(JPubUtils.IsEmpty(func)) {
                jsScript.append("var input = await session.getInput({ timeout: 10 });").append("\n\t");
            }
            else{
                func="var input = await session."+func+";";
                jsScript.append(func).append("\n\t");
            }
            jsScript.append("Log.Debug(\"script.getinput: \" + input);").append("\n\t");
            jsScript.append("var { dtmf, speech } = JSON.parse(input);").append("\n\t");
            jsScript.append("Log.Debug(\"script.getspeech: \" + speech);").append("\n\t");
            jsScript.append("var speechobj = JSON.parse(speech);").append("\n\t");
            jsScript.append("var speechtxt = speechobj.result;").append("\n\t");

            if(cti_ivrasrAutoSave) {
                jsScript.append("if(speechtxt){").append("\n\t\t");
                jsScript.append("var data = {speaker:\"cust\",callcaseid:v_callcaseId,content:speechtxt};").append("\n\t\t");
                jsScript.append("ScriptData.saveData(\"robot\", \"session\", \"savedialogue\", data);").append("\n\t");
                jsScript.append("}").append("\n\t");
            }

            JSONObject preNode=nextNode;
            JSONObject noNode=null;
            nextNode=findNextIfNode(nodes,edges,getNodeId(preNode),"Y");
            String yval=getNodeValue(nextNode);
            jsScript.append("var isyes=false;").append("\n\t");
            if(JPubUtils.IsNotEmpty(yval)){
                //jsScript.append("var pattern=new RegExp(\""+yval+"\");").append("\n\t");
                //jsScript.append("if(pattern.match(speechtxt)){").append("\n\t\t");
                jsScript.append("var pattern="+yval+";").append("\n\t");
                jsScript.append("var matchno = speechtxt.match(pattern);").append("\n\t");
                jsScript.append("Log.Debug(\"script.matchno=\"+matchno);").append("\n\t");
                jsScript.append("if(matchno){").append("\n\t\t");
                jsScript.append("isyes=true;").append("\n\t\t");
            }
            else{
                noNode=findNextIfNode(nodes,edges,getNodeId(preNode),"N");
                String nval=getNodeValue(noNode);
                //默认值
                if(JPubUtils.IsEmpty(nval)) nval="/(不|错)/";

                //jsScript.append("var pattern=new RegExp(\"" + nval + "\");").append("\n\t");
                //jsScript.append("if(!pattern.match(speechtxt)){").append("\n\t\t");
                jsScript.append("var pattern="+nval+";").append("\n\t");
                jsScript.append("var matchno = speechtxt.match(pattern);").append("\n\t");
                jsScript.append("Log.Debug(\"script.matchno=\"+matchno);").append("\n\t");
                jsScript.append("if(!matchno){").append("\n\t\t");
                jsScript.append("isyes=true;").append("\n\t\t");
            }
            //保存dial结果,对应字典：CAMPAIGN.CALLRESULT=是本人接收
            jsScript.append("setDialResult(v_caseId,'OK');").append("\n\t\t");
            //播报通知
            nextNodeID=findNextNodeID(edges,nextNode);
            nextNode=findNextNode(nodes,nextNodeID);
            addPlayNode(jsScript,nextNode,1);
            jsScript.append("}").append("\n\t");

            jsScript.append("await session.getInput({ timeout: 1 });").append("\n\t");

            jsScript.append("if(isyes){").append("\n\t\t");
            nextNodeID=findNextNodeID(edges,nextNode);
            nextNode=findNextNode(nodes,nextNodeID);
            addPlayNode(jsScript,nextNode,1);
            jsScript.append("}else{").append("\n\t\t");
            //保存dial结果,对应字典：CAMPAIGN.CALLRESULT=非本人接收
            jsScript.append("setDialResult(v_caseId,'NOTME');").append("\n\t\t");
            nextNodeID=findNextNodeID(edges,noNode);
            nextNode=findNextNode(nodes,nextNodeID);
            addPlayNode(jsScript,nextNode,1);
            jsScript.append("}").append("\n\t");
        }

        jsScript.append("session.hangup();").append("\n\t");

        jsScript.append("})();").append("\n\n");

        String ret=jsScript.toString();
        log.info("buildRobotScript:{}",ret);

        return new CmdResVo(1,ret);
    }
    private int getCont(StringBuilder jsScript,JSONObject p,int tcnt)
    {
        String nodeval=getNodeValue(p);
        jsScript.append("var content=\""+nodeval+"\";").append("\n\t");
        return 1;
    }

    private int addPlayNode(StringBuilder jsScript,JSONObject p,int tcnt)
    {
        String action=getNodeAction(p);
        String nodeval=getNodeValue(p);
        String func=getNodeFunc(p);

        String flag=getNodeFlag(p);
        if(JPubUtils.IsEqual(flag,"end")) {
            jsScript.append("Log.Debug(\"script.addPlayNode end.\");").append("\n\t");
            return 0;
        }
        if(JPubUtils.IsNotEmpty(action)) {
            jsScript.append("var data = getData(\"robot\", \"play\", \"" + action + "\", {caseid:v_caseId,txt:\"" + nodeval + "\"});").append("\n\t");
            if (tcnt > 0) AddTabKey(jsScript,tcnt);
            //jsScript.append("await waitConnect();").append("\n\t");
            jsScript.append("var content=data.content;").append("\n\t");
        }
        else{
            jsScript.append("var content=\""+nodeval+"\";").append("\n\t");
        }
        if(tcnt>0) AddTabKey(jsScript,tcnt);
        if(cti_ivrasrAutoSave) {
            jsScript.append("var data = {speaker:\"ivr\",callcaseid:v_callcaseId,content:content};").append("\n\t");
            if (tcnt > 0) AddTabKey(jsScript,tcnt);
            jsScript.append("ScriptData.saveData(\"robot\", \"session\", \"savedialogue\", data);").append("\n\t");
            if (tcnt > 0) AddTabKey(jsScript,tcnt);
        }
        if(JPubUtils.IsEmpty(func)) {
            jsScript.append("var respstr=speakwithDetect(dnis,content);").append("\n\t");
            if(tcnt>0) AddTabKey(jsScript,tcnt);
            jsScript.append("if(respstr){").append("\n\t\t");
            if(tcnt>0) AddTabKey(jsScript,tcnt);
            jsScript.append("var respjson = JSON.parse(respstr);").append("\n\t\t");
            if(tcnt>0) AddTabKey(jsScript,tcnt);
            jsScript.append("Log.Debug(\"Script.playFile:\"+tts_playurl+respjson.wavfile);").append("\n\t\t");
            if(tcnt>0) AddTabKey(jsScript,tcnt);
            jsScript.append("session.playFile(tts_playurl+respjson.wavfile, 1);").append("\n\t");
            if(tcnt>0) AddTabKey(jsScript,tcnt);
            jsScript.append("await session.getInput({ timeout: 1 });").append("\n\t\t");
            jsScript.append("}").append("\n\t");
        }
        else{
            func="session."+func+";";
            jsScript.append(func).append("\n\t");
        }

        return 1;
    }

    private void AddTabKey(StringBuilder jsScript,int cnt)
    {
        for(int i=0;i<cnt;i++){
            jsScript.append("\t");
        }
    }

    private JSONObject findNodeByFlag(JSONArray nodes,String nodeflag)
    {
        for(int i=0;i<nodes.size();i++){
            JSONObject o=nodes.getJSONObject(i);
            String nflag=getNodeFlag(o);
            if(JPubUtils.IsEqual(nflag,nodeflag)){
                return o;
            }
        }
        return null;
    }

    private String findNextNodeID(JSONArray edges,JSONObject p)
    {
        String oid=p.getString("id");
        for(int i=0;i<edges.size();i++){
            JSONObject o=edges.getJSONObject(i);
            String sourceNodeId=o.getString("sourceNodeId");
            if(JPubUtils.IsEqual(oid,sourceNodeId)){
                return o.getString("targetNodeId");
            }
        }
        return "";
    }

    private JSONObject findNextNode(JSONArray nodes,String nextid)
    {
        for(int i=0;i<nodes.size();i++){
            JSONObject o=nodes.getJSONObject(i);
            String oid=o.getString("id");
            if(JPubUtils.IsEqual(oid,nextid)){
                return o;
            }
        }
        return null;
    }

    private JSONObject findNextIfNode(JSONArray nodes,JSONArray edges,String sid,String action)
    {
        log.info("findNextIfNode：sid={},action={}",sid,action);
        for(int i=0;i<nodes.size();i++){
            JSONObject o=nodes.getJSONObject(i);
            String act=getNodeAction(o);
            String nid=getNodeId(o);
            if(JPubUtils.IsEqual(act,action)){
                if(isNodeLineTo(edges,sid,nid)) {
                    return o;
                }
            }
        }
        log.warn("findNextIfNode：sid={},action={},NoFind",sid,action);

        return null;
    }

    //找到回答结果是连接的此ifelse节点
    private boolean isNodeLineTo(JSONArray edges,String sid,String tid)
    {
        for(int i=0;i<edges.size();i++){
            JSONObject o=edges.getJSONObject(i);
            String sourceNodeId=o.getString("sourceNodeId");
            String targetNodeId=o.getString("targetNodeId");
            log.info("isNodeLineTo：sid={}/{},tid={}/{}",sid,sourceNodeId,tid,targetNodeId);
            if(JPubUtils.IsEqual(sid,sourceNodeId)&&JPubUtils.IsEqual(tid,targetNodeId)){
                return true;
            }
        }
        return false;
    }

    private String getNodeType(JSONObject p)
    {
        return p.getJSONObject("properties").getString("type");
    }

    private String getNodeAction(JSONObject p)
    {
        return p.getJSONObject("properties").getString("action");
    }

    private String getNodeValue(JSONObject p)
    {
        return p.getJSONObject("properties").getString("value");
    }

    private String getNodeFlag(JSONObject p)
    {
        return p.getJSONObject("properties").getString("flag");
    }

    private String getNodeFunc(JSONObject p)
    {
        return p.getJSONObject("properties").getString("func");
    }
    private String getNodeId(JSONObject p)
    {
        return p.getString("id");
    }

}




